package com.zjy.business.login.manager.service.impl;

import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.zjy.business.login.domain.manager.form.ManagerLoginForm;
import com.zjy.business.login.domain.manager.form.ManagerUserEditInfoForm;
import com.zjy.business.login.domain.manager.vo.ManagerLoginVo;
import com.zjy.business.login.domain.manager.vo.ManagerUserInfoVo;
import com.zjy.business.login.manager.service.ManagerSysAuthService;
import com.zjy.business.system.common.SysPermissionCommon;
import com.zjy.business.system.dao.SysMenuDao;
import com.zjy.business.system.dao.SysRoleMenuDao;
import com.zjy.business.system.dao.SysUserDao;
import com.zjy.business.system.dao.SysUserRoleDao;
import com.zjy.business.system.domain.entity.SysMenu;
import com.zjy.business.system.domain.entity.SysUser;
import com.zjy.business.system.domain.manager.form.ManagerSysEditPasswordForm;
import com.zjy.business.system.domain.manager.vo.ManagerSysMenuListVo;
import com.zjy.common.constant.BusinessConstant;
import com.zjy.common.constant.EntityConstant;
import com.zjy.common.constant.StatusEnums;
import com.zjy.common.domain.model.RequestHolder;
import com.zjy.common.utils.ConvertBeanUtils;
import com.zjy.common.utils.StreamUtils;
import com.zjy.common.utils.VirtualThreadUtils;
import com.zjy.web.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author yxb
 * create_time: 2024-10-23 09:42
 * description: 
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class ManagerSysAuthServiceImpl implements ManagerSysAuthService {

    final private SysUserDao sysUserDao;

    final private SysMenuDao sysMenuDao;
    private final SysUserRoleDao sysUserRoleDao;
    private final SysRoleMenuDao sysRoleMenuDao;
    private final SysPermissionCommon sysPermissionCommon;


    @Override
    public ManagerLoginVo formLogin(ManagerLoginForm form) {
        String username = form.getUsername();
        SysUser user = sysUserDao.lambdaQuery()
                .eq(SysUser::getAccount, username)
                .one();
        if (Objects.isNull(user)) {
            throw BusinessException.EXCEPTION("用户名或密码错误");
        }
        // 校验密码
        checkFormPassword(form.getPassword(), user.getPassword());
        // 校验用户状态
        if (!Objects.equals(user.getStatus(), StatusEnums.PUBLIC_STATUS_NORMAL.getStatus())) {
            throw BusinessException.EXCEPTION("账号已被禁用");
        }
        log.info("用户{}登录成功", username);
        // 生成token
        StpUtil.login(user.getId(), SaLoginConfig.setExtra(BusinessConstant.LOGIN_USER_TYPE_KEY, StatusEnums.LOGIN_USER_TYPE_ADMIN.getStatusStr()));
        ManagerLoginVo loginVo = new ManagerLoginVo();
        loginVo.setAccessToken(StpUtil.getTokenValue());
        loginVo.setExpireTime(StpUtil.getTokenTimeout());
        VirtualThreadUtils.runAsync(() -> {
            // 异步更新用户登录时间
            updateUserLoginTime(user.getId());
        });
        return loginVo;
    }

    @Override
    public ManagerUserInfoVo getUserInfo() {
        Long adminUserId = RequestHolder.getAdminUserId();
        SysUser user = sysUserDao.findCacheOne(SysUser::getId, adminUserId);
        if (Objects.isNull(user)) {
            throw BusinessException.EXCEPTION("用户不存在");
        }
        if (!Objects.equals(user.getStatus(), StatusEnums.PUBLIC_STATUS_NORMAL.getStatus())) {
            throw BusinessException.EXCEPTION("账号已被禁用");
        }
        ManagerUserInfoVo convert = ConvertBeanUtils.convert(user, ManagerUserInfoVo.class);
        convert.setRoleList(StpUtil.getRoleList());
        convert.setPermissionList(StpUtil.getPermissionList());
        return convert;
    }

    @Override
    public void editUserInfo(ManagerUserEditInfoForm form) {
        Long adminUserId = RequestHolder.getAdminUserId();
        SysUser sysUser = sysUserDao.findCacheOne(SysUser::getId, adminUserId);
        sysUser.setNickName(form.getNickName());
        sysUser.setEmail(form.getEmail());
        sysUser.setPhone(form.getPhone());
        sysUser.setSex(form.getSex());
        sysUser.setAvatar(form.getAvatar());
        sysUserDao.updateByIdUpdateCache(sysUser, SysUser::getId, adminUserId);
    }

    @Override
    public List<ManagerSysMenuListVo> queryMenuList() {
        return getMenuList(RequestHolder.getAdminUserId());
    }

    @Override
    public void editPassword(ManagerSysEditPasswordForm form) {
        Long adminUserId = RequestHolder.getAdminUserId();
        SysUser sysUser = sysUserDao.findCacheOne(SysUser::getId, adminUserId);
        // 校验旧密码
        if (!StringUtils.equals(DigestUtil.md5Hex(form.getOldPassword()), sysUser.getPassword())) {
            throw BusinessException.EXCEPTION("旧密码错误");
        }
        if (StringUtils.equals(DigestUtil.md5Hex(form.getNewPassword()), sysUser.getPassword())) {
            throw BusinessException.EXCEPTION("新密码不能与旧密码一致");
        }
        sysUser.setPassword(DigestUtil.md5Hex(form.getNewPassword()));
        // 更新用户
        sysUserDao.updateByIdUpdateCache(sysUser, SysUser::getId, adminUserId);
    }

    /**
     * 获取菜单列表
     * @return
     */
    private List<ManagerSysMenuListVo> getMenuList(Long adminUserId) {
        List<Long> menuIds;
        if (sysPermissionCommon.isSuperAdmin(adminUserId)) {
            menuIds = StreamUtils.toList(sysMenuDao.lambdaQuery()
                    .eq(SysMenu::getStatus, StatusEnums.PUBLIC_STATUS_NORMAL.getStatus())
                    .ne(SysMenu::getMenuType, StatusEnums.MENU_TYPE_BUTTON.getStatusStr())
                    .select(SysMenu::getId)
                    .list(), SysMenu::getId);
        } else {
            menuIds = sysRoleMenuDao.queryMenuIdByUserId(adminUserId);
        }

        Map<Long, List<ManagerSysMenuListVo>> menuMap = new HashMap<>();

        Map<Long, SysMenu> menuMapData = sysMenuDao.findCacheOneByMoreParam(SysMenu::getId, menuIds);
        menuMapData.values().forEach(item -> {
            if (Objects.equals(item.getStatus(), StatusEnums.PUBLIC_STATUS_NORMAL.getStatus())
                    && !Objects.equals(item.getMenuType(), StatusEnums.MENU_TYPE_BUTTON.getStatusStr())) {
                List<ManagerSysMenuListVo> list = menuMap.getOrDefault(item.getParentId(), new ArrayList<>());
                list.add(ConvertBeanUtils.convert(item, ManagerSysMenuListVo.class));
                menuMap.put(item.getParentId(), list);
            }
        });
        if (menuMap.isEmpty()) {
            return List.of();
        }
        return sysMenuDao.getSysMenuList(EntityConstant.FATHER_ID, menuMap);
    }

    /**
     * 校验密码
     * @param formPassword 表单密码
     * @param dbPassword 数据库密码
     */
    private void checkFormPassword(String formPassword, String dbPassword) {
        if (!StringUtils.equals(DigestUtil.md5Hex(formPassword), dbPassword)) {
            throw BusinessException.EXCEPTION("用户名或密码错误");
        }
    }

    /**
     * 更新用户登录时间
     * @param userId 用户id
     */
    private void updateUserLoginTime(Long userId) {
        SysUser sysUser = sysUserDao.findCacheOne(SysUser::getId, userId);
        sysUser.setLoginDate(new Date());
        sysUserDao.updateByIdUpdateCache(sysUser, SysUser::getId, userId);
    }
}
